package com.sangmo.fts;

import com.sangmo.boot.framework.data.json.context.ExtJsonMessageConverter;
import com.sangmo.boot.framework.plugin.dataview.validator.IDataViewValidator;
import com.sangmo.boot.framework.plugin.dataview.validator.impl.ApiMetaAspect;
import com.sangmo.boot.framework.plugin.dataview.validator.violation.DataValidationException;
import com.sangmo.boot.framework.plugin.dataview.validator.violation.DataViolation;
import com.sangmo.fts.config.ApiServlet;
import com.sangmo.fts.config.CoreFrameworkFilter;
import com.sangmo.fts.config.ProjectApiExceptionResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Configuration
public class DefaultApiConfig extends SpringBootServletInitializer {

    @Value("${upload.filePath}")
    private String uploadFilePath;

    @Bean
    public WebMvcConfigurer mvcConfigurer() {

        return new WebMvcConfigurer() {
            @Autowired
            IDataViewValidator dataViewValidator;

            @Override
            public void configurePathMatch(PathMatchConfigurer configurer) {
                configurer.setUseSuffixPatternMatch(false);
                configurer.setUseTrailingSlashMatch(true);
            }

            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("*")
                        .allowCredentials(true)
                        .maxAge(3600L);
            }


            @Override
            public Validator getValidator() {
                return new Validator() {
                    @Override
                    public boolean supports(Class<?> clazz) {
                        return true;
                    }

                    @Override
                    public void validate(Object target, Errors errors) {
                        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
                        boolean isMeta = null != request.getParameter("_meta");
                        boolean isDocs = null != request.getParameter("_docs");
                        if (!isMeta && !isDocs) {
                            Set<DataViolation> rets = dataViewValidator.validate(target, false);
                            if (null != rets && !rets.isEmpty()) {
                                throw new DataValidationException(rets);
                            }
                        }
                    }
                };
            }

//            @Override
//            public void addInterceptors(InterceptorRegistry registry) {
//                    registry.addInterceptor(accessLimitInterceptor());
//            }
        };
    }

//    @Bean
//    public AccessLimitInterceptor accessLimitInterceptor() {
//        return new AccessLimitInterceptor();
//    }

    @Bean
    public ServletRegistrationBean apiServlet() {
        DispatcherServlet servlet = new ApiServlet();
        servlet.setThrowExceptionIfNoHandlerFound(true);

        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
        servlet.setApplicationContext(applicationContext);

        ServletRegistrationBean bean = new ServletRegistrationBean(servlet, "/*");
        bean.setName("defaultApi");
        Map<String, String> params = new HashMap<>();
        params.put("detectAllHandlerExceptionResolvers", "true");
        params.put("contextConfigLocation", "classpath*:spring/defaultApi.xml");
        bean.setInitParameters(params);
        bean.setLoadOnStartup(1);
        return bean;
    }
    /*@Bean
    public FilterRegistrationBean characterEncodingFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setForceEncoding(true);
        characterEncodingFilter.setEncoding("UTF-8");
        registrationBean.setFilter(characterEncodingFilter);
        return registrationBean;
    }*/

    @Bean
    public FilterRegistrationBean shiroFilterBean(){
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setName("security");
        bean.setFilter(new DelegatingFilterProxy("shiroFilter"));
        bean.addInitParameter("targetFilterLifecycle","true");
        bean.addUrlPatterns("/*");
        bean.setOrder(-99);
        return bean;
    }

    @Bean
    public FilterRegistrationBean frameworkFilterBean(){
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setName("framework");
        bean.setFilter(new DelegatingFilterProxy(new CoreFrameworkFilter()));
        bean.addUrlPatterns("/*");
        bean.setOrder(-100);
        return bean;
    }

    @Bean
    public HandlerExceptionResolver apiExceptionResolver() {
        return new ProjectApiExceptionResolver();
    }

    @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter converter = new ExtJsonMessageConverter();
        return converter;
    }

    @Bean
    public ApiMetaAspect apiMetaAspect() {
        return new ApiMetaAspect();
    }
}
